#include "datacollector.h"
#include "rstatagent.h"
#include <QDebug>

DataCollector *DataCollector::m_dataCollector = NULL;

DataCollector::DataCollector(QObject *parent) :
    QObject(parent)
{
	qRegisterMetaType<TGenConfig>("TGenConfig");
	qRegisterMetaType<TTranData>("TTranData");
	qRegisterMetaType<TProfile>("TProfile");
	qRegisterMetaType<TRstatData>("TRstatData");
	qRegisterMetaType<std::string>("std::string");
	qRegisterMetaType<QList<TTranData> >("QList<TTranData>");
	addRstatAgent();
}

DataCollector *DataCollector::GetInstance()
{
	if(m_dataCollector == NULL){
		m_dataCollector = new DataCollector();
	}
	return m_dataCollector;
}

void DataCollector::addRstatAgent()
{
	QThread *thread = new QThread();
	RstatAgent *agent = new RstatAgent("localhost");
	
	// from agent to this
	QObject::connect(this, SIGNAL(setServerIP(std::string)), agent, SLOT(SetServerIP(std::string)));
	QObject::connect(agent, SIGNAL(rstatDataArrived(TRstatData)), this, SLOT(RstatDataArrviedHandle(TRstatData)));
	QObject::connect(thread, SIGNAL(started()), agent, SLOT(InitAgent()));

	agent->moveToThread(thread);
	thread->start();
}

// slots
void DataCollector::AddAgent(int genId, const TGenConfig& config)
{
	// check if GenAgent of genId already exists
	for(int i = 0; i < m_agentList.count(); i ++){
		if(m_agentList[i]->getGenId() == genId)
			return;
	}

	QThread *thread = new QThread();
	GenAgent *agent = new GenAgent(genId, config);

	// from agent to this
	QObject::connect(agent, SIGNAL(connectCompleted(int, int)), this, SLOT(ConnectCompletedHandle(int, int)));
	QObject::connect(agent, SIGNAL(commandCompleted(int, int, int)), this, SLOT(CommandCompletedHandle(int, int, int)));
	QObject::connect(agent, SIGNAL(tranDataArrived(int, QList<TTranData>)), this, SLOT(TranDataArrivedHandle(int, QList<TTranData>)));
	QObject::connect(agent, SIGNAL(userDataArrived(int, int)), this, SLOT(UserDataArrivedHandle(int, int)));

	// from this to agent
	QObject::connect(this, SIGNAL(sendCommand(int, int)), agent, SLOT(SendCommand(int, int)));
	QObject::connect(this, SIGNAL(sendProfile(TProfile)), agent, SLOT(SendProfile(TProfile)));
	QObject::connect(this, SIGNAL(connectGen(int, TGenConfig)), agent, SLOT(ConnectGenerator(int, TGenConfig)));

	m_threadList.append(thread);
	m_agentList.append(agent);

	QObject::connect(thread, SIGNAL(started()), agent, SLOT(InitAgent()));

	agent->moveToThread(thread);
	thread->start();
}

void DataCollector::DelAgent(int genId)
{
	for(int i = 0; i < m_agentList.count(); i ++){
		if(m_agentList[i]->getGenId() == genId){
			delete m_agentList[i];
			delete m_threadList[i];
			m_agentList.removeAt(i);
			m_threadList.removeAt(i);
			break;
		}
	}
}

void DataCollector::StopAgent(int genId)
{
	for(int i = 0; i < m_agentList.count(); i ++){
		if(m_agentList[i]->getGenId() == genId){
			m_threadList[i]->exit();
		}
	}
}

void DataCollector::StartAgent()
{
	ConfigData *configdata = ConfigData::GetInstance();
	// send profile first
	TProfile profile;
	profile.duration = configdata->getDuration();
	profile.inc_user = configdata->getIncUser();
	profile.inc_times = configdata->getIncTime();

	emit sendProfile(profile);
	qDebug() << "sending profile ...";
}

void DataCollector:: ConnectCompletedHandle(int genId, int status)
{
	emit connectCompleted(genId, status);
}

void DataCollector:: CommandCompletedHandle(int genId, int cmdType, int status)
{
	emit commandCompleted(genId, cmdType, status);
	if(cmdType == PROFILE_REP){
		qDebug() << "Gen(" << genId << ") completed sending profile, starting agent ...";
		emit sendCommand(genId, RUN_REQ);
	}
}

void DataCollector:: RstatDataArrviedHandle(TRstatData rstatData)
{
	emit rstatDataArrived(rstatData);
}

void DataCollector:: TranDataArrivedHandle(int genId, QList<TTranData> incTranData)
{
	emit tranDataArrived(genId, incTranData);

	static int updateRate = ConfigData::GetInstance()->getUpdateRate();
	static int genCounter = 0, timeCounter = 0;
	static int genArray[MaxGenCount] = {0};
	static QList<TTranData> sumTranData;
	static TTranData zeroTranData = {0, 0};

	if(sumTranData.empty()){
		for(int i = 0; i < incTranData.count(); i ++){
			sumTranData.append(zeroTranData);
		}
	}

	if(genArray[genId] == 0){
		genArray[genId] = 1;
		genCounter ++;
	} else {
		qDebug() << "genId conflict, genId = " << genId;
		return;
	}
	for(int i = 0; i < sumTranData.count(); i ++){
		sumTranData[i].tps += incTranData[i].tps;
		sumTranData[i].resp += incTranData[i].resp;
	}
	// all agent ready
	if(genCounter >= m_agentList.count()){
		timeCounter ++;
		genCounter = 0;
		for(int i = 0; i < MaxGenCount; i ++)
			genArray[i] = 0;
	}

	// ready to emit 
	if(timeCounter >= updateRate){
		// calculate the average tps
		for(int i = 0; i < sumTranData.count(); i ++){
			sumTranData[i].tps /= updateRate;
		}
		emit sumTranDataArrived(sumTranData);
		timeCounter = 0;
		for(int i = 0; i < sumTranData.count(); i ++){
			sumTranData[i].tps = 0;
			sumTranData[i].resp = 0;
		}
		updateRate = ConfigData::GetInstance()->getUpdateRate();
	}
}

void DataCollector:: UserDataArrivedHandle(int genId, int incUser)
{
	emit userDataArrived(genId, incUser);

	static int updateRate = ConfigData::GetInstance()->getUpdateRate();
	static int genCounter = 0, timeCounter = 0;
	static int genArray[MaxGenCount] = {0};
	static int sumUser = 0, genSumUser = 0;

	if(genArray[genId] == 0){
		genArray[genId] = 1;
		genCounter ++;
	} else {
		qDebug() << "genId conflict, genId = " << genId;
		return;
	}
	genSumUser += incUser;

	// all agent ready
	if(genCounter >= m_agentList.count()){
		timeCounter ++;
		genCounter = 0;
		for(int i = 0; i < MaxGenCount; i ++)
			genArray[i] = 0;
		// user number at this point
		sumUser = genSumUser;
		genSumUser = 0;
	}

	// ready to emit, user need not be zeroed
	if(timeCounter >= updateRate){
		emit sumUserDataArrived(sumUser);
		timeCounter = 0;
		sumUser = 0;
		updateRate = ConfigData::GetInstance()->getUpdateRate();
	}
}

void DataCollector::SetServerIP(std::string ip)
{
	emit setServerIP(ip);
}
